package com.skyline.imagine.web;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import com.skyline.imagine.exception.FileStoreException;
import com.skyline.imagine.exception.ImageProcessFailedException;
import com.skyline.imagine.exception.NotImageException;
import com.skyline.imagine.exception.StorageUnreachableException;
import com.skyline.imagine.image.GMImageOperations;
import com.skyline.imagine.image.ImageInfo;
import com.skyline.imagine.image.ResultState;
import com.skyline.imagine.storage.FastDFSFileOperator;

@Component
public class SwfUploadAction {
	private static final Log logger = LogFactory.getLog(SwfUploadAction.class);

	private final Map<String, Object> noFileExistErrMsg = new HashMap<String, Object>(3, 1f);
	private final Map<String, Object> storeFailedErrMsg = new HashMap<String, Object>(3, 1f);

	@Autowired
	private FastDFSFileOperator fileOperator;
	@Autowired
	private GMImageOperations imageOperations;
	@Value("imagine.uploadResize")
	private Boolean resize;
	@Value("imagine.uploadResizeSize")
	private int resizeBaseSize;
	@Value("imagine.localUploadPath")
	private String uploadTempDir;

	public SwfUploadAction() {
		toJsonMap(false, ResultState.NO_FILE_EXIST.toString(), "上传文件失败！文件内容为空，请重新上传", noFileExistErrMsg);
		toJsonMap(false, ResultState.STORE_FAILED.toString(), "保存文件失败！", storeFailedErrMsg);
	}

	public Map<String, Object> getNoFileExistErrMsg() {
		return noFileExistErrMsg;
	}

	public Map<String, Object> fileUpload(MultipartHttpServletRequest request) {
		List<MultipartFile> files = request.getFiles("file");

		if (files == null || files.isEmpty()) {
			return noFileExistErrMsg;
		}

		List<Map<String, Object>> results = new ArrayList<Map<String, Object>>(files.size());
		boolean allSuccess = true;
		boolean allFailed = true;

		for (MultipartFile file : files) {
			if (!file.isEmpty()) {
				Map<String, Object> result = null;

				String errCode = ResultState.UNKOWN_FAILED.toString();
				String errMsg = "上传图片失败！";

				try {
					result = uploadFile(file);
					allFailed = false;

					errCode = ResultState.SUCCESS.toString();
					errMsg = "上传图片成功！";
				} catch (NotImageException e) {
					errCode = ResultState.NOT_IMAGE.toString();
					errMsg = "上传图片失败！上传文件不是图片";
					logger.warn(errMsg, e);
				} catch (ImageProcessFailedException e) {
					errMsg = "上传图片失败！图片压缩失败";
					errCode = ResultState.PROCESS_IMAGE_FAILED.toString();
					logger.warn(errMsg, e);
				} catch (StorageUnreachableException e) {
					errMsg = "上传图片失败！保存失败";
					errCode = ResultState.STORE_FAILED.toString();
					logger.warn(errMsg, e);
				} catch (FileStoreException e) {
					errMsg = "上传图片失败！保存失败";
					errCode = ResultState.STORE_FAILED.toString();
					logger.warn(errMsg, e);
				} catch (IOException e) {
					errMsg = "上传图片失败！保存失败";
					errCode = ResultState.STORE_FAILED.toString();
					logger.warn(errMsg, e);
				}

				if (result == null) {
					allSuccess = false;
					result = new HashMap<String, Object>(2, 1f);
				}

				result.put("errcode", errCode);
				result.put("errmsg", errMsg);

				results.add(result);

			} else {
				allSuccess = false;

				Map<String, Object> result = new HashMap<String, Object>(2, 1f);
				result.put("errcode", ResultState.NO_FILE_EXIST.toString());
				result.put("errmsg", "图片内容为空！");

				results.add(result);
			}
		}

		if (allFailed) {// 上传全部失败
			return storeFailedErrMsg;
		} else if (results.size() == 1) {// 只上传一张图片
			Map<String, Object> result = results.get(0);

			String errorCode = (String) result.get("errcode");
			String errorMsg = (String) result.get("errmsg");

			boolean success = ResultState.SUCCESS.toString().equals(errorCode);

			return toJsonMap(success, errorCode, errorMsg, result);
		} else {
			Map<String, Object> resultMap = new HashMap<String, Object>(6, 1f);
			resultMap.put("allSuccess", allSuccess);
			resultMap.put("allFailed", allFailed);
			resultMap.put("results", results);

			return toJsonMap(true, "", "", resultMap);
		}

	}

	/**
	 * 
	 * @param file
	 * @return
	 * @throws IOException
	 * @throws NotImageException
	 * @throws ImageProcessFailedException
	 * @throws StorageUnreachableException
	 * @throws FileStoreException
	 */
	private Map<String, Object> uploadFile(MultipartFile file) throws IOException {
		UploadTempFile tempFile = getTempFile(file);
		ImageInfo imageInfo = identifyFile(tempFile.getStoreLocation());

		UploadTempFile resizeTempFile = null;
		if (resize) {
			resizeTempFile = resizeFile(tempFile.getStoreLocation(), imageInfo, resizeBaseSize);
		}

		String[] remoteInfos = null;
		if (resizeTempFile == null) {
			remoteInfos = fileOperator.uploadFile(file.getBytes(), imageInfo.getExt());
		} else {
			remoteInfos = fileOperator.uploadFile(resizeTempFile.getStoreLocation(), imageInfo.getExt());
		}

		if (remoteInfos == null || remoteInfos.length != 2) {
			throw new FileStoreException("无法获取上传文件的返回信息");
		}

		Map<String, Object> result = new HashMap<String, Object>(4, 1f);
		result.put("group", remoteInfos[0]);
		result.put("path", remoteInfos[1]);

		return result;
	}

	private ImageInfo identifyFile(File file) throws NotImageException {
		String filePath = file.getAbsolutePath();
		return imageOperations.showImageInfo(filePath);
	}

	private UploadTempFile resizeFile(File file, ImageInfo imageInfo, int baseSize) {
		String srcURL = file.getAbsolutePath();
		String destURL = FilenameUtils.removeExtension(srcURL) + "_resize" + FilenameUtils.getExtension(srcURL);

		ResultState state = imageOperations.resizeImage(srcURL, destURL, baseSize,
				imageOperations.isExtMultiFrame(imageInfo.getExt()));
		if (state != ResultState.SUCCESS) {
			throw new ImageProcessFailedException("图片压缩失败！");
		}

		return new UploadTempFile(new File(destURL), true);
	}

	private UploadTempFile getTempFile(MultipartFile file) throws IOException {
		UploadTempFile tempFile = null;
		File storeLocation = null;

		if (file instanceof CommonsMultipartFile) {
			CommonsMultipartFile commonFile = (CommonsMultipartFile) file;
			FileItem fileItem = commonFile.getFileItem();
			if (fileItem instanceof DiskFileItem) {
				storeLocation = ((DiskFileItem) fileItem).getStoreLocation();
				if (storeLocation.exists()) {
					tempFile = new UploadTempFile(storeLocation, false);
				}
			}
		}

		if (tempFile == null) {
			if (storeLocation != null) { // 小于写入临时文件阈值，则强制写一次。
				FileUtils.writeByteArrayToFile(storeLocation, file.getBytes());
				tempFile = new UploadTempFile(storeLocation, false);
			} else { // 非DiskFileItem
				FileUtils.writeByteArrayToFile(UploadTempFile.createStoreLocation(uploadTempDir), file.getBytes());
				tempFile = new UploadTempFile(storeLocation, true);
			}
		}

		return tempFile;
	}

	private Map<String, Object> toJsonMap(boolean isSuccess, String errorCode, String errorMsg,
			Map<String, Object> srcMsg) {
		if (srcMsg == null) {
			srcMsg = new HashMap<String, Object>(3, 1f);
		}
		srcMsg.put("errflag", isSuccess);
		srcMsg.put("errcode", errorCode);
		srcMsg.put("errmsg", errorMsg);
		return srcMsg;
	}

}
